/**
 * 
 */
package org.jenkon.commons.io.utils;

import java.io.File;
import java.io.FileFilter;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.jenkon.commons.io.filter.AllFileFilter;
import org.jenkon.commons.io.filter.AndFileFilter;
import org.jenkon.commons.io.filter.IsDirectoryFileFilter;
import org.jenkon.commons.io.filter.IsFileFileFilter;
import org.jenkon.commons.lang.Assert;

/**
 * util class with helping methods for {@link File}.
 * 
 * @author Jens Konopka
 * 
 */
public final class FileUtils {

	/**
	 * hide public constructor for this util class.
	 */
	private FileUtils() {
	}

	/**
	 * @param file {@link File}
	 * @param reference {@link File}
	 * @return if file is newer reference then <code>true</code> other <code>false</code>
	 * @see #isFileNewer(File, Date)
	 * @see #isFileNewer(File, long)
	 */
	public static boolean isFileNewer(final File file, final File reference) {
		return isFileNewer(file, reference.lastModified());
	}

	/**
	 * @param file {@link File}
	 * @param date {@link Date}
	 * @return if file is newer reference then <code>true</code> other <code>false</code>
	 * @see #isFileNewer(File, long)
	 */
	public static boolean isFileNewer(final File file, final Date date) {
		return isFileNewer(file, date.getTime());
	}

	/**
	 * @param file {@link File}
	 * @param millis milliseconds to check
	 * @return if file is newer reference then <code>true</code> other <code>false</code>
	 */
	public static boolean isFileNewer(final File file, final long millis) {
		return file.lastModified() > millis;
	}

	/**
	 * @param file {@link File}
	 * @param reference {@link File}
	 * @return if file is older reference the <code>true</code> other <code>false</code>
	 * @see #isFileNewer(File, Date)
	 * @see #isFileNewer(File, long)
	 */
	public static boolean isFileOlder(final File file, final File reference) {
		return isFileOlder(file, reference.lastModified());
	}

	/**
	 * @param file {@link File}
	 * @param date {@link Date}
	 * @return if file is older reference the <code>true</code> other <code>false</code>
	 * @see #isFileNewer(File, long)
	 */
	public static boolean isFileOlder(final File file, final Date date) {
		return isFileOlder(file, date.getTime());
	}

	/**
	 * @param file {@link File}
	 * @param millis milliseconds to check if older
	 * @return if file is older reference the <code>true</code> other <code>false</code>
	 */
	public static boolean isFileOlder(final File file, final long millis) {
		return file.lastModified() < millis;
	}

	/**
	 * get the recursive size of file. include all children files and directories.
	 * 
	 * @param file {@link File}
	 * @return size of file
	 */
	public static long sizeOf(final File file) {
		long size = 0;
		if (file.isDirectory()) {
			final File[] files = file.listFiles();
			for (final File children : files) {
				size += sizeOf(children);
			}
		} else {
			size = file.length();
		}
		return size;
	}

	public static List<File> getFiles(final File dir) throws Exception {
		return getFiles(dir, new AllFileFilter());
	}

	public static List<File> getFiles(final File dir, final boolean recursive) throws Exception {
		return getFiles(dir, recursive, new AllFileFilter());
	}

	public static List<File> getFiles(final File dir, final FileFilter filter) throws Exception {
		return getFiles(dir, false, filter);
	}

	public static List<File> getFiles(final File dir, final boolean recursive, final FileFilter filter)
			throws Exception {
		
		Assert.isTrue(dir.isDirectory(), dir + " is not a directory.");

		final List<File> files = new ArrayList<File>();

		if (recursive) {

			for (final File file : dir.listFiles(new IsDirectoryFileFilter())) {
				files.addAll(getFiles(file, recursive, filter));
			}

		}

		final AndFileFilter andFileFilter = new AndFileFilter();
		andFileFilter.add(new IsFileFileFilter());
		andFileFilter.add(filter);

		for (final File file : dir.listFiles(andFileFilter)) {
			files.add(file);
		}

		return files;

	}

}
